1 // Tencent is pleased to support the open source community by making RapidJSON available.
3 // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
5 // Licensed under the MIT License (the "License"); you may not use this file except
6 // in compliance with the License. You may obtain a copy of the License at
8 // http://opensource.org/licenses/MIT
10 // Unless required by applicable law or agreed to in writing, software distributed
11 // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
12 // CONDITIONS OF ANY KIND, either express or implied. See the License for the
13 // specific language governing permissions and limitations under the License.
15 #ifndef RAPIDJSON_INTERNAL_STACK_H_
16 #define RAPIDJSON_INTERNAL_STACK_H_
18 #include "../allocators.h"
22 #if defined(__clang__)
24 RAPIDJSON_DIAG_OFF(c++98-compat)
27 RAPIDJSON_NAMESPACE_BEGIN
30 ///////////////////////////////////////////////////////////////////////////////
33 //! A type-unsafe stack for storing different types of data.
34 /*! \tparam Allocator Allocator for allocating stack memory.
36 template <typename Allocator>
39 // Optimization note: Do not allocate memory for stack_ in constructor.
40 // Do it lazily when first Push() -> Expand() -> Resize().
41 Stack(Allocator* allocator, size_t stackCapacity) : allocator_(allocator), ownAllocator_(0), stack_(0), stackTop_(0), stackEnd_(0), initialCapacity_(stackCapacity) {
44 #if RAPIDJSON_HAS_CXX11_RVALUE_REFS
46 : allocator_(rhs.allocator_),
47 ownAllocator_(rhs.ownAllocator_),
49 stackTop_(rhs.stackTop_),
50 stackEnd_(rhs.stackEnd_),
51 initialCapacity_(rhs.initialCapacity_)
54 rhs.ownAllocator_ = 0;
58 rhs.initialCapacity_ = 0;
66 #if RAPIDJSON_HAS_CXX11_RVALUE_REFS
67 Stack& operator=(Stack&& rhs) {
72 allocator_ = rhs.allocator_;
73 ownAllocator_ = rhs.ownAllocator_;
75 stackTop_ = rhs.stackTop_;
76 stackEnd_ = rhs.stackEnd_;
77 initialCapacity_ = rhs.initialCapacity_;
80 rhs.ownAllocator_ = 0;
84 rhs.initialCapacity_ = 0;
90 void Swap(Stack& rhs) RAPIDJSON_NOEXCEPT {
91 internal::Swap(allocator_, rhs.allocator_);
92 internal::Swap(ownAllocator_, rhs.ownAllocator_);
93 internal::Swap(stack_, rhs.stack_);
94 internal::Swap(stackTop_, rhs.stackTop_);
95 internal::Swap(stackEnd_, rhs.stackEnd_);
96 internal::Swap(initialCapacity_, rhs.initialCapacity_);
99 void Clear() { stackTop_ = stack_; }
103 // If the stack is empty, completely deallocate the memory.
104 Allocator::Free(stack_); // NOLINT (+clang-analyzer-unix.Malloc)
113 // Optimization note: try to minimize the size of this function for force inline.
114 // Expansion is run very infrequently, so it is moved to another (probably non-inline) function.
116 RAPIDJSON_FORCEINLINE void Reserve(size_t count = 1) {
117 // Expand the stack if needed
118 if (RAPIDJSON_UNLIKELY(static_cast<std::ptrdiff_t>(sizeof(T) * count) > (stackEnd_ - stackTop_)))
123 RAPIDJSON_FORCEINLINE T* Push(size_t count = 1) {
125 return PushUnsafe<T>(count);
129 RAPIDJSON_FORCEINLINE T* PushUnsafe(size_t count = 1) {
130 RAPIDJSON_ASSERT(stackTop_);
131 RAPIDJSON_ASSERT(static_cast<std::ptrdiff_t>(sizeof(T) * count) <= (stackEnd_ - stackTop_));
132 T* ret = reinterpret_cast<T*>(stackTop_);
133 stackTop_ += sizeof(T) * count;
138 T* Pop(size_t count) {
139 RAPIDJSON_ASSERT(GetSize() >= count * sizeof(T));
140 stackTop_ -= count * sizeof(T);
141 return reinterpret_cast<T*>(stackTop_);
146 RAPIDJSON_ASSERT(GetSize() >= sizeof(T));
147 return reinterpret_cast<T*>(stackTop_ - sizeof(T));
151 const T* Top() const {
152 RAPIDJSON_ASSERT(GetSize() >= sizeof(T));
153 return reinterpret_cast<T*>(stackTop_ - sizeof(T));
157 T* End() { return reinterpret_cast<T*>(stackTop_); }
160 const T* End() const { return reinterpret_cast<T*>(stackTop_); }
163 T* Bottom() { return reinterpret_cast<T*>(stack_); }
166 const T* Bottom() const { return reinterpret_cast<T*>(stack_); }
168 bool HasAllocator() const {
169 return allocator_ != 0;
172 Allocator& GetAllocator() {
173 RAPIDJSON_ASSERT(allocator_);
177 bool Empty() const { return stackTop_ == stack_; }
178 size_t GetSize() const { return static_cast<size_t>(stackTop_ - stack_); }
179 size_t GetCapacity() const { return static_cast<size_t>(stackEnd_ - stack_); }
183 void Expand(size_t count) {
184 // Only expand the capacity if the current stack exists. Otherwise just create a stack with initial capacity.
188 ownAllocator_ = allocator_ = RAPIDJSON_NEW(Allocator)();
189 newCapacity = initialCapacity_;
191 newCapacity = GetCapacity();
192 newCapacity += (newCapacity + 1) / 2;
194 size_t newSize = GetSize() + sizeof(T) * count;
195 if (newCapacity < newSize)
196 newCapacity = newSize;
201 void Resize(size_t newCapacity) {
202 const size_t size = GetSize(); // Backup the current size
203 stack_ = static_cast<char*>(allocator_->Realloc(stack_, GetCapacity(), newCapacity));
204 stackTop_ = stack_ + size;
205 stackEnd_ = stack_ + newCapacity;
209 Allocator::Free(stack_);
210 RAPIDJSON_DELETE(ownAllocator_); // Only delete if it is owned by the stack
213 // Prohibit copy constructor & assignment operator.
215 Stack& operator=(const Stack&);
217 Allocator* allocator_;
218 Allocator* ownAllocator_;
222 size_t initialCapacity_;
225 } // namespace internal
226 RAPIDJSON_NAMESPACE_END
228 #if defined(__clang__)
232 #endif // RAPIDJSON_STACK_H_